#include "HighPrecisionTimer.h"

HighPrecisionTimer::HighPrecisionTimer() {
#ifdef _WIN32
    QueryPerformanceFrequency(&m_start.win32);
    m_freq = m_start.win32.QuadPart;
#else
    m_freq = 1000000000ULL;
#endif
    INIT_MUTEX(&m_mutex);
}

HighPrecisionTimer::~HighPrecisionTimer() {
    DESTROY_MUTEX(&m_mutex);
}

void HighPrecisionTimer::start() {
    LOCK_MUTEX(&m_mutex);
#ifdef _WIN32
    QueryPerformanceCounter(&m_start.win32);
#else
    clock_gettime(CLOCK_MONOTONIC, &m_start.posix);
#endif
    UNLOCK_MUTEX(&m_mutex);
}

void HighPrecisionTimer::stop() {
    LOCK_MUTEX(&m_mutex);
#ifdef _WIN32
    QueryPerformanceCounter(&m_end.win32);
#else
    clock_gettime(CLOCK_MONOTONIC, &m_end.posix);
#endif
    UNLOCK_MUTEX(&m_mutex);
}

uint64_t HighPrecisionTimer::elapsedNanoSeconds() const {
    LOCK_MUTEX(&m_mutex);
    uint64_t elapsed = 0;
#ifdef _WIN32
    uint64_t delta = m_end.win32.QuadPart - m_start.win32.QuadPart;
    uint64_t seconds = delta / m_freq;
    uint64_t remainder = delta % m_freq;
    elapsed = (static_cast<uint64_t>(seconds) * 1000000000ui64) + (static_cast<uint64_t>(remainder) * 1000000000ui64 / m_freq);
#else
    long sec = m_end.posix.tv_sec - m_start.posix.tv_sec;
    long nsec = m_end.posix.tv_nsec - m_start.posix.tv_nsec;
    elapsed = sec * 1000000000ULL + nsec;
#endif
    UNLOCK_MUTEX(&m_mutex);
    return elapsed;
}